package com.bsj.power.job.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsj.power.common.config.cached.BindCardCached;
import com.bsj.power.common.config.cached.PersonnelCached;
import com.bsj.power.common.config.cached.RedisCached;
import com.bsj.power.common.config.cached.WorkPersonnelCached;
import com.bsj.power.common.config.exception.ApiException;
import com.bsj.power.common.config.global.JsonResult;
import com.bsj.power.common.config.global.JsonResultEnum;
import com.bsj.power.common.config.redis.RedisConstant;
import com.bsj.power.common.constant.ApiConstants;
import com.bsj.power.common.constant.NumericalConstants;
import com.bsj.power.common.constant.UWBPosConstant;
import com.bsj.power.common.def.dto.PageDTO;
import com.bsj.power.common.def.dto.alarmReport.AlarmReportSearchDTO;
import com.bsj.power.common.def.dto.cardReport.BindCardDTO;
import com.bsj.power.common.def.dto.job.*;
import com.bsj.power.common.def.entity.Panel;
import com.bsj.power.common.def.entity.Scene;
import com.bsj.power.common.def.entity.alarmReport.AlarmReport;
import com.bsj.power.common.def.entity.gb28181.Device;
import com.bsj.power.common.def.entity.job.Job;
import com.bsj.power.common.def.entity.job.JobPersonnel;
import com.bsj.power.common.def.entity.job.QualityPlan;
import com.bsj.power.common.def.entity.job.WorkPersonnel;
import com.bsj.power.common.def.entity.log.SysRecordLog;
import com.bsj.power.common.def.entity.personGroup.BindPersonGroup;
import com.bsj.power.common.def.entity.personGroup.PersonGroup;
import com.bsj.power.common.def.entity.personnel.Personnel;
import com.bsj.power.common.def.entity.room.Room;
import com.bsj.power.common.def.vo.JobRemindVO;
import com.bsj.power.common.def.vo.pls.AlarmReportVO;
import com.bsj.power.common.def.vo.pls.WorkPersonnelVO;
import com.bsj.power.common.def.vo.pls.httpVo.HttpQualityPlanVO;
import com.bsj.power.common.def.vo.pls.httpVo.HttpTagPosVO;
import com.bsj.power.common.def.vo.web.job.JobPageVO;
import com.bsj.power.common.def.vo.web.job.JobVO;
import com.bsj.power.common.def.vo.web.job.home.AreaCount;
import com.bsj.power.common.def.vo.web.job.home.CompleteNumDay;
import com.bsj.power.common.def.vo.web.job.home.JobRank;
import com.bsj.power.common.def.vo.web.job.home.WorkDuration;
import com.bsj.power.common.def.vo.web.job.media.BackTimeMediaVO;
import com.bsj.power.common.file.log.OperateLogRead;
import com.bsj.power.common.http.PersonHttp;
import com.bsj.power.common.mapper.*;
import com.bsj.power.common.util.DataUtil;
import com.bsj.power.common.util.DateUtils;
import com.bsj.power.common.util.FindMediaDevUtils;
import com.bsj.power.common.util.ParamCheckUtil;
import com.bsj.power.job.service.JobService;
import com.bsj.tools.DateUntil;
import com.bsj.writeFile.def.DataVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.bsj.power.common.config.aspect.LogAspect.LOG_ID;
import static com.bsj.power.common.util.DateUtils.yearMonthDay;

/**
 * @author yinhao
 * @version 1.0
 * @description 工单信息
 * @date 2024/5/10
 */
@Service
@Slf4j
public class JobServiceImpl implements JobService {

    @Value("${sync.jobUrl}")
    private String syncJobUrl;

    @Autowired
    private RedisCached redisCached;

    @Resource
    private JobMapper jobMapper;

    @Resource
    private PersonnelMapper personnelMapper;

    @Resource
    private JobPersonnelMapper jobPersonnelMapper;

    @Resource
    private AlarmReportMapper alarmReportMapper;

    @Resource
    private PathMapper pathMapper;

    @Resource
    private SceneMapper sceneMapper;

    @Resource
    private QualityPlanMapper qualityPlanMapper;

    @Resource
    private WorkPersonnelMapper workPersonnelMapper;

    @Autowired
    private OperateLogRead operateLogRead;

    @Autowired
    private BindCardCached bindCardCached;

    @Autowired
    private PersonnelCached personnelCached;

    @Resource
    private PersonGroupMapper personGroupMapper;

    @Resource
    private RoomMapper roomMapper;

    @Autowired
    private WorkPersonnelCached workPersonnelCached;

    @Resource
    private DeviceMapper deviceMapper;

    @Autowired
    private PersonHttp personHttp;

    /**
     * 新增作业信息
     *
     * @param vo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long addAndUpdateJob(JobDTO vo) {
        Long jobId = vo.getJobId();
        Job job = new Job();
        String sceneStr = redisCached.get(RedisConstant.REDIS_SCENE_INFO + vo.getWorkArea());
        if (StringUtils.isBlank(sceneStr)) {
            throw new ApiException(JsonResultEnum.FAIL, "场景不存在");
        }
        Integer directorId = vo.getDirectorId();
        if (personnelMapper.selectOne(Wrappers.<Personnel>lambdaQuery().eq(Personnel::getDirectorId, directorId)) == null) {
            throw new ApiException(JsonResultEnum.FAIL, "负责人id不存在");
        }
        BeanUtil.copyProperties(vo, job);
        if (vo.getStartTime() != null) {
            job.setStartTime(DateUntil.strToDate(vo.getStartTime()));
        }
        if (vo.getEndTime() != null) {
            job.setEndTime(DateUntil.strToDate(vo.getEndTime()));
        }
        List<String> personnelList = vo.getPersonnel();
        //获取作业工单里授权的作业人员信息
        List<Integer> personnelIdList = new ArrayList<>();
        if (personnelList != null) {
            QueryWrapper<Personnel> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().in(Personnel::getName, personnelList);
            List<Personnel> list = personnelMapper.selectList(queryWrapper);
            personnelIdList = list.stream().map(Personnel::getPersonnelId).collect(Collectors.toList());
        }
        List<QualityPlan> qualityPlans = vo.getQualityPlans();
        if (jobId == null) {
            //新增
            jobMapper.insert(job);
            if (!personnelIdList.isEmpty()) {
                jobPersonnelMapper.batchInserts(Map.of("jobId", job.getJobId(), "list", personnelIdList));
            }
            //质量计划添加
            if (!CollectionUtils.isEmpty(qualityPlans)) {
                qualityPlans = qualityPlans.stream().map(qualityPlan -> {
                    qualityPlan.setJobNum(job.getJobNum());
                    return qualityPlan;
                }).collect(Collectors.toList());
                qualityPlanMapper.batchAdd(qualityPlans);
            }
        } else {
            //修改
            jobMapper.updateById(job);
            if (!personnelIdList.isEmpty()) {
                jobPersonnelMapper.deleteById(jobId);
                jobPersonnelMapper.batchInserts(Map.of("jobId", job.getJobId(), "list", personnelIdList));
            }
        }
        //将最新的作业信息写入缓存
        Job jobInfo = jobMapper.selectById(job.getJobId());
        QueryWrapper<JobPersonnel> query = new QueryWrapper<>();
        query.lambda().eq(JobPersonnel::getJobId, job.getJobId());
        //查询该作业绑定的人员信息
        List<JobPersonnel> jobPersonnelList = jobPersonnelMapper.selectList(query);
        List<Integer> personnelIds = jobPersonnelList.stream().map(JobPersonnel::getPersonnelId).collect(Collectors.toList());
        jobInfo.setPersonnelIds(personnelIds);
        redisCached.hset(RedisConstant.JOB_ORDER_INFO_KEY, job.getJobId() + "", JSON.toJSONString(jobInfo));
        //每天工单同步过来的信息
//        jobInfo.setPathId(path.getPathId());
        jobInfo.setQualityPlans(qualityPlans);
        String dateKey = DateUtils.dateToStr(yearMonthDay, new Date());
        redisCached.hset(RedisConstant.JOB_ORDER_EVERYDAY_KEY + dateKey, jobInfo.getJobNum(), JSON.toJSONString(jobInfo));
        return jobId;
    }

    /**
     * 修改作业信息
     *
     * @param job
     * @return
     */
    @Override
    public int updateJobInfo(Job job) {
        return jobMapper.updateById(job);
    }

    /**
     * 按条件查询工单信息
     *
     * @param jobSearch
     * @return
     */
    @Override
    public List<Job> selectJobList(JobSearch jobSearch) {
        QueryWrapper<Job> queryWrapper = new QueryWrapper<>();
        return jobMapper.selectList(queryWrapper.lambda()
                .between(Job::getStartTime, jobSearch.getStartTime(), jobSearch.getEndTime())
                .like(Job::getJobNum, jobSearch.getJobNo()));
    }

    /**
     * 分页查询工单信息
     *
     * @param dto
     * @return
     */
    @Override
    public JsonResult<List<JobVO>> jobPageList(JobSearchDTO dto) {
        IPage<Job> page = new Page<>(dto.getPageNumber(), dto.getPageSize());
        QueryWrapper<Job> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().ne(Job::getStatus, NumericalConstants.TWO);
        if (dto.getStartTime() != null && dto.getEndTime() != null) {
            queryWrapper.lambda().gt(Job::getEndTime, dto.getEndTime());
        }
        if (StringUtils.isNotEmpty(dto.getJobNum())) {
            queryWrapper.lambda().like(Job::getJobNum, dto.getJobNum());
        }
        if (StringUtils.isNotBlank(dto.getRoomNo())) {
            queryWrapper.lambda().like(Job::getRoomNo, dto.getRoomNo());
        }
        //中高风险区域
        if (dto.getHighRisk() != null) {
            queryWrapper.lambda().in(Job::getRiskLevel, List.of(NumericalConstants.TWO, NumericalConstants.THREE));

            //            //查询高危区域
//            List<Scene> paths = sceneMapper.selectList(new QueryWrapper<Scene>().lambda().eq(Scene::getSensitived, 1));
//            if (paths.isEmpty()) {
//                return JsonResult.success();
//            }
//            List<String> pathNameList = paths.stream().map(Scene::getSceneName).collect(Collectors.toList());
//            queryWrapper.lambda().in(Job::getWorkArea, pathNameList);
        }
        Date date = new Date();
        queryWrapper.lambda().orderByDesc(Job::getCreateTime);
        IPage<Job> iPage = jobMapper.selectPage(page, queryWrapper);
        List<Job> records = iPage.getRecords();
        Map<String, Long> deviceNumMap = null;
        if (!CollectionUtils.isEmpty(records)) {
            List<String> roomNos = records.stream().map(Job::getRoomNo).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(roomNos)) {
                List<Device> devices = deviceMapper.selectList(Wrappers.<Device>lambdaQuery().in(Device::getRoomNo, roomNos));
                if (!CollectionUtils.isEmpty(devices)) {
                    deviceNumMap = devices.stream().collect(Collectors.groupingBy(Device::getRoomNo, Collectors.counting()));
                }
            }
        }
        List<JobVO> dataList = new ArrayList<>();
        for (Job item : records) {
            List<WorkPersonnel> personnelLists = jobPersonnelMapper.selectJobIdByPersonnelList(item.getJobId());
            JobVO jobVO = new JobVO();
            BeanUtil.copyProperties(item, jobVO);
            List<Integer> personnelIds = null;
            Map<Integer, PersonGroup> personGroupMap = null;
            //作业人员信息
            if (personnelLists != null && !personnelLists.isEmpty()) {
                List<String> empNos = personnelLists.stream().map(WorkPersonnel::getTemporaryEmpNo).collect(Collectors.toList());
                List<Integer> groupIds = personnelLists.stream().map(WorkPersonnel::getGroupId).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(groupIds)) {
                    List<PersonGroup> personGroups = personGroupMapper.selectList(Wrappers.<PersonGroup>lambdaQuery()
                            .in(PersonGroup::getGroupId, groupIds).eq(PersonGroup::getGroupType, NumericalConstants.TWO));
                    if (!CollectionUtils.isEmpty(personGroups)) {
                        personGroupMap = personGroups.stream().collect(Collectors.toMap(PersonGroup::getGroupId, Function.identity()));
                    }
                }
                //位置信息点
                Map<String, HttpTagPosVO> posVOMap = bindCardCached.hGetEmpNoBindPos(empNos);
                List<WorkPersonnelVO> personnelVOList = new ArrayList<>();
                for (WorkPersonnel pl : personnelLists) {
                    WorkPersonnelVO personnelVO = new WorkPersonnelVO();
                    BeanUtil.copyProperties(pl, personnelVO);
                    if (posVOMap != null) {
                        HttpTagPosVO httpTagPosVO = posVOMap.get(pl.getTemporaryEmpNo());
                        personnelVO.setTagPos(httpTagPosVO);
                    }
                    personnelVO.setAge(getAgeByIdCodeNo(pl.getIdCardNo()));
                    if (!CollectionUtils.isEmpty(personGroupMap)) {
                        PersonGroup personGroup = personGroupMap.get(pl.getGroupId());
                        if (personGroup != null) {
                            personnelVO.setGroupName(personGroup.getGroupName());
                        }
                    }
                    personnelVOList.add(personnelVO);
                }
                jobVO.setPersonnel(personnelVOList);
                personnelIds = personnelLists.stream().map(WorkPersonnel::getWorkPersonnelId).collect(Collectors.toList());
            }
            //作业区域场景信息
            Scene scene = sceneMapper.selectOne(Wrappers.<Scene>lambdaQuery().eq(Scene::getSceneName, item.getWorkArea()));
            jobVO.setScene(scene);
            //工作时长
            Date startTime = item.getStartTime();
            Date endTime = item.getEndTime();
            if (endTime == null) {
                endTime = date;
            }
            Double hour = DateUtils.minusDateToHour(startTime, endTime);
            //有计划开始时间大于当前时间的情况，而结束时间又为空；或结束时间小于开始时间的情况（同步过来的数据就是如此），所以运行时长为负的话再取负值
            hour = hour != null ? Math.abs(hour) : hour;
            jobVO.setRunTime(hour + "");
            //质量计划信息
            jobVO.setQualityPlans(qualityPlanMapper.selectList(Wrappers.<QualityPlan>lambdaQuery().eq(QualityPlan::getJobNum, jobVO.getJobNum())));
            //报警数
            if (!CollectionUtils.isEmpty(personnelIds)) {
                QueryWrapper<AlarmReport> queryAlarm = new QueryWrapper<>();
                queryAlarm.lambda().in(AlarmReport::getPersonnelId, personnelIds);
                queryAlarm.lambda().between(AlarmReport::getBeginTime, item.getStartTime(), item.getEndTime());
                Long alarmCount = alarmReportMapper.selectCount(queryAlarm);
                jobVO.setAlarmNum(alarmCount);
            }
            jobVO.setStartTime(DateUtils.dateToStr(startTime));
            if (endTime != null) {
                jobVO.setEndTime(DateUtils.dateToStr(endTime));
            }
            String roomNo = item.getRoomNo();
            Long deviceNum = 0L;
            //设备数
            if (!CollectionUtils.isEmpty(deviceNumMap)) {
                if (StringUtils.isNotBlank(roomNo) && deviceNumMap.get(roomNo) != null) {
                    deviceNum = deviceNumMap.get(roomNo);
                }

            }
            jobVO.setDeviceNum(deviceNum);
            //TODO 标记数
            dataList.add(jobVO);
        }
        records.stream().forEach(item -> {

        });
        return JsonResult.success(dataList, iPage.getTotal());
    }

    /**
     * 获取报警列表
     *
     * @param dto
     * @return
     */
    @Override
    public JsonResult<List<AlarmReportVO>> jobAlarmReport(AlarmReportSearchDTO dto) {
        //先获取作业数据
        Job job = jobMapper.selectById(dto.getJobId());
        if (job == null) {
            throw new ApiException(JsonResultEnum.JOB_INFO_IS_NULL);
        }
        QueryWrapper<JobPersonnel> queryPersonnel = new QueryWrapper<>();
        queryPersonnel.lambda().eq(JobPersonnel::getJobId, job.getJobId());
        //查询该作业绑定的人员信息
        List<JobPersonnel> jobPersonnelList = jobPersonnelMapper.selectList(queryPersonnel);
        List<Integer> personnelIds = jobPersonnelList.stream().map(JobPersonnel::getPersonnelId).collect(Collectors.toList());
        if (personnelIds.isEmpty()) {
            return JsonResult.success();
        }
        //根据人员ID与作业开始和结束时间查询报警
        IPage<AlarmReport> page = new Page<>(dto.getPageNumber(), dto.getPageSize());
        LambdaQueryWrapper<AlarmReport> queryWrapper = Wrappers.<AlarmReport>lambdaQuery()
                .in(AlarmReport::getPersonnelId, personnelIds)
                .between(AlarmReport::getBeginTime, job.getStartTime(), job.getEndTime())
                .orderByDesc(AlarmReport::getBeginTime);
        IPage<AlarmReport> iPage = alarmReportMapper.selectPage(page, queryWrapper);
        List<AlarmReportVO> data = new ArrayList<>();
        iPage.getRecords().stream().forEach(item -> {
            AlarmReportVO reportVO = new AlarmReportVO();
            BeanUtil.copyProperties(item, reportVO);
            reportVO.setBeginTime(DateUtils.dateToStr(item.getBeginTime()));
            reportVO.setEndTime(DateUtils.dateToStr(item.getEndTime()));
            data.add(reportVO);
        });
        return JsonResult.success(data, iPage.getTotal());
    }

    /**
     * 作业板块数据统计第一栏
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     */
    @Override
    public JsonResult<JobPageVO> doJobDataPageOne(String startTime, String endTime) {
        List<Job> jobs = jobMapper.selectList(Wrappers.<Job>lambdaQuery().orderByDesc(Job::getCreateTime));
        //今日完成率
        Double nowRate = 0D;
        // 获取当前天开始和结束的时间
        Date now = new Date();
        Date nowStart = DateUtils.getStartOfDay(now);
        Date nowEnd = DateUtils.getEndOfDay(now);
        //当前天所有的作业总数
        long nowCount = jobs.stream().filter(item -> item.getEndTime() != null
                && item.getStartTime().getTime() >= nowStart.getTime()
                && item.getEndTime().getTime() <= nowEnd.getTime()).count();
        //当前天已完成的作业数
        long completeCount = jobs.stream().filter(item -> item.getEndTime() != null
                && item.getStartTime().getTime() >= nowStart.getTime()
                && item.getEndTime().getTime() <= nowEnd.getTime()
                && item.getStatus().equals(NumericalConstants.TWO)).count();
        //计算今日完成率
        if (nowCount > 0) {
            nowRate = NumberUtil.div(completeCount, nowCount, 2);
        }
        //按照区域将数据分组 key为区域名称 value为区域作业数量
        Map<String, Long> areaTotal = jobs.stream().filter(job -> StringUtils.isNotBlank(job.getWorkArea())).collect(Collectors.groupingBy(Job::getWorkArea, Collectors.counting()));
        List<AreaCount> areaCount = new ArrayList<>();
        for (Map.Entry<String, Long> entry : areaTotal.entrySet()) {
            AreaCount count = AreaCount.builder()
                    .name(entry.getKey())
                    .count(entry.getValue())
                    .build();
            areaCount.add(count);
        }
        //根据开始时间和结束时间计算近几日作业列表，如果时间没有，则查询近7天的
        List<String> dateAfter = new LinkedList<>();
        if (StringUtils.isAnyBlank(startTime, endTime)) {
            Date ago = DateUtils.nDaysAgo(LocalDateTime.now(), 6);
            dateAfter = DateUtils.getDateAfter(ago, now);
        } else {
            dateAfter = DateUtils.getDateAfter(startTime, endTime);
        }
        List<CompleteNumDay> completeNumDayList = new ArrayList<>();
        for (int i = dateAfter.size() - 1; i >= 0; i--) {
//            //real time
//            Date day = DateUtils.nDaysAgo(LocalDateTime.now(), i);
//            // 获取当前天开始和结束的时间
//            Date start = DateUtils.getStartOfDay(day);
//            Date end = DateUtils.getEndOfDay(day);
//            //当前天所有的作业总数
//            long realCount = jobs.stream().filter(item -> item.getStartTime() != null
//                    && item.getStartTime().getTime() >= start.getTime()
//                    && item.getEndTime().getTime() <= end.getTime()).count();
//            //当前天已完成的作业数
//            long realComplete = jobs.stream().filter(item -> item.getStartTime() != null
//                    && item.getStartTime().getTime() >= start.getTime()
//                    && item.getEndTime().getTime() <= end.getTime()
//                    && item.getStatus().equals(NumericalConstants.TWO)).count();
//            //计算完成率
//            String dateToStr = DateUtils.dateToStr(yearMonthDay, day);
//            Double completeRate = 0D;
//            if (nowCount > 0 && realCount > 0) {
//                completeRate = NumberUtil.div(realComplete, realCount, 2);
//            }
//            completeNumDayList.add(CompleteNumDay.builder().time(dateToStr).rate(Double.parseDouble(String.format("%.2f", completeRate))).build());


            String dateStr = dateAfter.get(i);
            Date start = DateUtils.getStartTime(dateStr);
            Date end = DateUtils.getEndTime(dateStr);
//            //real time
//            Date day = DateUtils.nDaysAgo(LocalDateTime.now(), i);
//            // 获取当前天开始和结束的时间
//            Date start = DateUtils.getStartOfDay(day);
//            Date end = DateUtils.getEndOfDay(day);
            //当前天所有的作业总数
            long realCount = jobs.stream().filter(item -> item.getEndTime() != null
                    && item.getStartTime().getTime() >= start.getTime()
                    && item.getEndTime().getTime() <= end.getTime()).count();
            //当前天已完成的作业数
            long realComplete = jobs.stream().filter(item -> item.getEndTime() != null
                    && item.getStartTime().getTime() >= start.getTime()
                    && item.getEndTime().getTime() <= end.getTime()
                    && item.getStatus().equals(NumericalConstants.TWO)).count();
            //计算完成率
//            String dateToStr = DateUtils.dateToStr(yearMonthDay, day);
            Double completeRate = 0D;
            if (realComplete > 0 && realCount > 0) {
                completeRate = NumberUtil.div(realComplete, realCount, 2);
            }
            completeNumDayList.add(CompleteNumDay.builder().time(dateStr).rate(Double.parseDouble(String.format("%.2f", completeRate))).build());
        }
        //结果集
        JobPageVO jobPageVO = new JobPageVO();
        jobPageVO.setCompleteRate(Double.parseDouble(String.format("%.2f", nowRate)));
        //TODO 暂时取前十
        if (!CollectionUtils.isEmpty(areaCount)) {
            areaCount = areaCount.stream().sorted(Comparator.comparingLong(AreaCount::getCount).reversed()).collect(Collectors.toList());
            if (areaCount.size() > 10) {
                areaCount = areaCount.subList(0, 10);
            }
        }
        jobPageVO.setAreaCount(areaCount);
        jobPageVO.setCompleteNumDays(completeNumDayList);
        return JsonResult.success(jobPageVO);
    }

    /**
     * 作业板块数据统计第二栏
     *
     * @param classify [0]: 0-作业效率排行版团队 1-个人
     *                 [1]: 0-故障排行榜设备 1-区域
     * @return
     */
    @Override
    public JsonResult<JobPageVO> doJobDataPageTwo(Integer[] classify, String startTime, String endTime) {
        Integer classifyOne = classify[0];
        Integer classifyTwo = classify[1];
        //开始时间
        Date startDay = DateUtils.nDaysAgo(LocalDateTime.now(), 6);
        if (StringUtils.isNotEmpty(startTime)) {
            startDay = DateUtils.strToDate(startTime);
        }
        //结束时间
        Date endDay = new Date();
        if (StringUtils.isNotEmpty(endTime)) {
            endDay = DateUtils.strToDate(endTime);
        }
        //获取近7日的作业数据
        JobPageVO jobPageVO = new JobPageVO();
        List<Job> jobs = jobMapper.selectList(Wrappers.<Job>lambdaQuery()
                .between(Job::getStartTime, startDay, endDay)
                .orderByDesc(Job::getCreateTime));
        //效率排行(个人/团队)
        List<JobRank> jobRankList = new ArrayList<>();
        //按每日完成时长分组统计
        List<WorkDuration> workDurationList = new ArrayList<>();
        //个人效率
//        if (classifyOne == 1) {
        //计算效率
        calculationEfficiencyRanking(jobs, jobRankList);
//        }
        //已完成的作业
        List<Job> completeJobList = jobs.stream().filter(item -> item.getStatus() == 2 && item.getStartTime() != null && item.getEndTime() != null).collect(Collectors.toList());
        //设备|区域故障排行
        List<JobRank> faultRanks = malfunctionRankingList(completeJobList, classifyTwo);
        //时长运算
        calculateHomeworkDuration(completeJobList, workDurationList);
        if (!CollectionUtils.isEmpty(jobRankList)) {
            jobRankList = jobRankList.stream().sorted(Comparator.comparingDouble(JobRank::getRate).reversed()).collect(Collectors.toList());
            //TODO 暂时取前十
            if (jobRankList.size() > 10) {
                jobRankList = jobRankList.subList(0, 10);
            }
        }
        if (!faultRanks.isEmpty()) {
            faultRanks = faultRanks.stream().sorted(Comparator.comparingLong(JobRank::getTotal).reversed()).collect(Collectors.toList());
            //TODO 暂时取前十
            if (faultRanks.size() > 10) {
                faultRanks = faultRanks.subList(0, 10);
            }
        }
        jobPageVO.setEfficiencyRanks(jobRankList);
        jobPageVO.setFaultRanks(faultRanks);
        jobPageVO.setWorkDurations(workDurationList);
        return JsonResult.success(jobPageVO);
    }

    /**
     * 故障排行
     *
     * @param jobs
     * @param classifyTwo
     * @return java.util.List<com.bsj.power.common.def.vo.web.job.home.JobRank>
     * @author ljx
     * @time 2024/6/24 17:21
     */
    private List<JobRank> malfunctionRankingList(List<Job> jobs, Integer classifyTwo) {
        List<JobRank> faultRanks = new LinkedList<>();
        //设备故障
        if (classifyTwo.equals(NumericalConstants.ZERO)) {
            for (Job job : jobs) {
                List<JobPersonnel> jobPersonnelList = jobPersonnelMapper.selectList(Wrappers.<JobPersonnel>lambdaQuery().eq(JobPersonnel::getJobId, job.getJobId()));
                if (!CollectionUtils.isEmpty(jobPersonnelList)) {
                    List<Integer> personnelIds = jobPersonnelList.stream().map(JobPersonnel::getPersonnelId).collect(Collectors.toList());
                    List<JobRank> jobRankList = alarmReportMapper.countByPersonnelAndTime(personnelIds, job);
                    if (!CollectionUtils.isEmpty(jobRankList)) {
                        faultRanks.addAll(jobRankList);
                    }
                }
            }
        } else {
            //区域故障
            for (Job job : jobs) {
                JobRank jobRank = alarmReportMapper.countByAreaAndTime(job);
                if (jobRank != null && StringUtils.isNotBlank(jobRank.getName())) {
                    faultRanks.add(jobRank);
                }
            }
        }
        return faultRanks.stream().collect(Collectors.toMap(JobRank::getName, JobRank::getTotal, (v1, v2) -> v1 + v2)).entrySet().stream().map(map -> {
            return JobRank.builder().name(map.getKey()).total(map.getValue()).build();
        }).collect(Collectors.toList());
    }


    /**
     * 工单日志分页
     *
     * @param sysRecordLogDTO
     * @return com.bsj.power.common.config.global.JsonResult<java.util.List < com.bsj.power.common.def.entity.log.SysRecordLog>>
     * @author ljx
     * @time 2024/6/24 14:52
     */
    @Override
    public JsonResult<List<SysRecordLog>> logPage2(SysRecordLogDTO sysRecordLogDTO) {
        int total = 0;
        List<SysRecordLog> sysRecordLogs = new LinkedList<>();
        String title = sysRecordLogDTO.getTitle();
        Integer businessType = sysRecordLogDTO.getBusinessType();
        long start = DateUtils.strToDate(DateUtils.TIME_STANDARD_FORMAT, sysRecordLogDTO.getStartTime()).getTime();
        long end = DateUtils.strToDate(DateUtils.TIME_STANDARD_FORMAT, sysRecordLogDTO.getEndTime()).getTime();
        List<DataVo> list = operateLogRead.readVoAll(LOG_ID, start, end);
        if (CollectionUtils.isEmpty(list)) {
            return JsonResult.success(sysRecordLogs, total);
        }
        sysRecordLogs = list.stream().map(item -> {
            SysRecordLog sysRecordLog = JSON.parseObject(item.getContext(), SysRecordLog.class);
            return sysRecordLog;
        }).sorted(Comparator.comparing(SysRecordLog::getRecordTime).reversed()).collect(Collectors.toList());
        if (StringUtils.isNotBlank(title)) {
            sysRecordLogs = sysRecordLogs.stream().filter(sysRecordLog -> sysRecordLog.getTitle().equals(title)).collect(Collectors.toList());
        }
        if (businessType != null) {
            sysRecordLogs = sysRecordLogs.stream().filter(sysRecordLog -> sysRecordLog.getBusinessType().equals(businessType)).collect(Collectors.toList());
        }

        total = sysRecordLogs.size();
        sysRecordLogs = DataUtil.pagingByList(sysRecordLogs, sysRecordLogDTO.getPageSize(), sysRecordLogDTO.getPageNumber());
        sysRecordLogs.stream().forEach(item -> {
            Long recordTime = item.getRecordTime();
            if (recordTime != null) {
                item.setTime(DateUtils.dateToStr(new Date(recordTime)));
            }
        });
        return JsonResult.success(sysRecordLogs, total);
    }

    @Override
    public List<SysRecordLog> logPageExport(SysRecordLogDTO sysRecordLogDTO) {
        int total = 0;
        List<SysRecordLog> sysRecordLogs = new LinkedList<>();
        String title = sysRecordLogDTO.getTitle();
        Integer businessType = sysRecordLogDTO.getBusinessType();
        long start = DateUtils.strToDate(DateUtils.TIME_STANDARD_FORMAT, sysRecordLogDTO.getStartTime()).getTime();
        long end = DateUtils.strToDate(DateUtils.TIME_STANDARD_FORMAT, sysRecordLogDTO.getEndTime()).getTime();
        List<DataVo> list = operateLogRead.readVoAll(LOG_ID, start, end);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        sysRecordLogs = list.stream().map(item -> {
            SysRecordLog sysRecordLog = JSON.parseObject(item.getContext(), SysRecordLog.class);
            return sysRecordLog;
        }).sorted(Comparator.comparing(SysRecordLog::getRecordTime).reversed()).collect(Collectors.toList());
        if (StringUtils.isNotBlank(title)) {
            sysRecordLogs = sysRecordLogs.stream().filter(sysRecordLog -> sysRecordLog.getTitle().equals(title)).collect(Collectors.toList());
        }
        if (businessType != null) {
            sysRecordLogs = sysRecordLogs.stream().filter(sysRecordLog -> sysRecordLog.getBusinessType().equals(businessType)).collect(Collectors.toList());
        }

//        total = sysRecordLogs.size();
//        sysRecordLogs = DataUtil.pagingByList(sysRecordLogs, sysRecordLogDTO.getPageSize(), sysRecordLogDTO.getPageNumber());
        sysRecordLogs.stream().forEach(item -> {
            Long recordTime = item.getRecordTime();
            if (recordTime != null) {
                item.setTime(DateUtils.dateToStr(new Date(recordTime)));
            }
        });
        return sysRecordLogs;
    }


    /**
     * 时间追溯获取多媒体数据
     *
     * @param jobId 工单ID
     * @return
     */
    @Override
    public List<BackTimeMediaVO> backTime(Long jobId) {
        Job job = jobMapper.selectById(jobId);
        if (job == null) {
            throw new ApiException(JsonResultEnum.JOB_INFO_IS_NULL);
        }
        QueryWrapper<JobPersonnel> queryPersonnel = new QueryWrapper<>();
        queryPersonnel.lambda().eq(JobPersonnel::getJobId, job.getJobId());
        //查询该作业绑定的人员信息
        List<JobPersonnel> jobPersonnelList = jobPersonnelMapper.selectList(Wrappers.<JobPersonnel>lambdaQuery()
                .eq(JobPersonnel::getJobId, job.getJobId()));
        List<Integer> personnelIds = jobPersonnelList.stream().map(JobPersonnel::getPersonnelId).collect(Collectors.toList());
        if (personnelIds.isEmpty()) {
            return null;
        }
//        List<WorkPersonnel> workPersonnels = workPersonnelMapper.selectBatchIds(personnelIds);
        //使用作业人员工号去获取报警信息
//        List<String> workPerList = workPersonnels.stream().map(WorkPersonnel::getTemporaryEmpNo).collect(Collectors.toList());
        List<BackTimeMediaVO> backTimeMediaVOS = alarmReportMapper.selectBatchWorkPersonnel(Map.of("startTime", job.getStartTime(),
                "endTime", job.getEndTime(), "list", personnelIds));
        return backTimeMediaVOS;
    }

    /**
     * 质量计划同步
     *
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/7/11 10:20
     */
    @Override
    public JsonResult qualityPlanSync() {
        String str = HttpUtil.get(ApiConstants.GET_QUALITY_PLAN_INFO + "&wonum=");
        if (StringUtils.isNotBlank(str)) {
            JSONObject data = JSON.parseObject(str);
            Integer status = data.getInteger("status");
            if (status != null && status.equals(JsonResultEnum.SUCCESS.getCode())) {
                JSONArray jsonArray = data.getJSONArray("result");
                if (!CollectionUtils.isEmpty(jsonArray)) {
                    List<HttpQualityPlanVO> httpQualityPlanVOS = jsonArray.toJavaList(HttpQualityPlanVO.class);
                    if (!CollectionUtils.isEmpty(httpQualityPlanVOS)) {
                        List<QualityPlan> qualityPlans = httpQualityPlanVOS.stream().map(httpQualityPlanVO -> {
                            QualityPlan qualityPlan = new QualityPlan(httpQualityPlanVO);
                            String wpm1 = httpQualityPlanVO.getWpm1();
                            if (StringUtils.isNotBlank(wpm1)) {
                                qualityPlan.setQcType(wpm1ToType(wpm1));
                            }
                            //TODO QC状态、见证人未确认
                            return qualityPlan;
                        }).collect(Collectors.toList());
                        qualityPlanMapper.batchAdd(qualityPlans);
                    }
                }
            }
        }
        return null;
    }


//    /**
//     * 同步工单信息
//     *
//     * @param startTime 开始时间
//     * @param endTime   结束时间
//     */
//    @Override
//    public int syncSysJobList(String startTime, String endTime) {
//        WorkHttpDTO workHttpDTO = WorkHttpDTO.builder()
//                .pageNum(1)
//                .pageSize(1000)
//                .targstartdate(startTime)
//                .targcompdate(endTime)
//                .build();
//        List<Job> jobList = ExternalAccessHttp.workInfoHttpGet(syncJobUrl, workHttpDTO);
//        return jobMapper.syncInsertSysJobList(jobList);
//    }

    public static void main(String[] args) {
        String idCardNo = "430423200201050913";
        String year = idCardNo.substring(6, 10);
        String month = idCardNo.substring(10, 12);
        String day = idCardNo.substring(12, 14);
        System.out.println(year);
        System.out.println(month);
        System.out.println(day);
        System.out.println(year + "-" + month + "-" + day + " 00:00:00");
    }

    /**
     * 作业工单添加作业人员信息
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer addAndUpdateWorkPersonnel(WorkPersonnelDTO dto) {
        Integer workPersonnelId = dto.getWorkPersonnelId();
        Long jobId = dto.getJobId();
        Job job = null;
        if (jobId != null) {
            job = jobMapper.selectById(jobId);
            if (job == null) {
                throw new ApiException(JsonResultEnum.JOB_INFO_IS_NULL);
            }
        }
        //人员组校验
        Integer groupId = dto.getGroupId();
        if (groupId != null) {
            PersonGroup personGroup = personGroupMapper.selectOne(Wrappers.<PersonGroup>lambdaQuery()
                    .eq(PersonGroup::getGroupType, NumericalConstants.TWO).eq(PersonGroup::getGroupId, groupId));
            ParamCheckUtil.isNull(personGroup, JsonResultEnum.PERSON_GROUP_EXIST);
        } else {
            groupId = NumericalConstants.ZERO;
        }
        String idCardNo = dto.getIdCardNo();
        if (!Validator.isCitizenId(idCardNo)) {
            throw new ApiException(JsonResultEnum.ID_CARD_NO_FORMAT_ERROR);
        }
        WorkPersonnel workPersonnel = new WorkPersonnel();
        BeanUtil.copyProperties(dto, workPersonnel);
        workPersonnel.setGroupId(groupId);
        workPersonnel.setAge(getAgeByIdCodeNo(idCardNo));
        //新增
        if (workPersonnelId == null) {
            //身份证去重
            if (workPersonnelMapper.exists(Wrappers.<WorkPersonnel>lambdaQuery().eq(WorkPersonnel::getIdCardNo, idCardNo))) {
                throw new ApiException(JsonResultEnum.ID_CARD_NO_EXIST);
            }
            //给人员信息生成一个唯一工号
            String id = IdUtil.objectId();
            workPersonnel.setTemporaryEmpNo(id);
            //新增人员信息表数据
            workPersonnelMapper.insert(workPersonnel);
        } else {
            WorkPersonnel oldWorkPersonnel = workPersonnelMapper.selectById(workPersonnelId);
            ParamCheckUtil.isNull(oldWorkPersonnel, JsonResultEnum.PERSONNEL_NOT_EXIST);
            String temporaryEmpNo = oldWorkPersonnel.getTemporaryEmpNo();
            //身份证去重
            if (workPersonnelMapper.exists(Wrappers.<WorkPersonnel>lambdaQuery().eq(WorkPersonnel::getIdCardNo, idCardNo)
                    .ne(WorkPersonnel::getWorkPersonnelId, workPersonnelId))) {
                throw new ApiException(JsonResultEnum.ID_CARD_NO_EXIST);
            }
            workPersonnel.setTemporaryEmpNo(temporaryEmpNo);
            //修改人员信息
            workPersonnelMapper.updateById(workPersonnel);
            if (groupId != null && !groupId.equals(NumericalConstants.ZERO)) {
                BindPersonGroup bindPersonGroup = new BindPersonGroup(workPersonnel);
                redisCached.hset(RedisConstant.GROUP_PERSONNEL_INFO + groupId, workPersonnel.getTemporaryEmpNo(), JSON.toJSONString(bindPersonGroup));
            } else {
                redisCached.hdel(RedisConstant.GROUP_PERSONNEL_INFO + oldWorkPersonnel.getGroupId(), temporaryEmpNo);
            }
//            String oldIdCardNo = oldWorkPersonnel.getIdCardNo();
//            String extEventPersonNo = null;
            //身份证号修改的情况
//            if (StringUtils.isNotBlank(idCardNo) && StringUtils.isNotBlank(oldIdCardNo) && !idCardNo.equals(oldIdCardNo)) {
//                extEventPersonNo = personHttp.getExtEventPersonNoByIdCardNo(idCardNo);
//                if (StringUtils.isNotBlank(extEventPersonNo)) {
//                    personnelMapper.updateById(new Personnel(workPersonnelId, extEventPersonNo));
//                }
//            }
            //防止绑卡后修改作业人员导致退卡时人员信息校验不通过
            BindCardDTO oldBindCardDTO = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_EMP_NO_KEY + temporaryEmpNo);
            if (oldBindCardDTO != null) {
                oldBindCardDTO.setIdCardNo(idCardNo);
                oldBindCardDTO.setPersonnelName(workPersonnel.getName());
                oldBindCardDTO.setPhone(workPersonnel.getPhone());
//                修改绑卡信息
//                if (StringUtils.isNotBlank(extEventPersonNo)) {
//                    //旧人员编号
//                    String oldExtEventPersonNo = oldBindCardDTO.getExtEventPersonNo();
//                    if (StringUtils.isNotBlank(oldExtEventPersonNo)) {
//                        //删除旧的安防平台人员编号缓存
//                        redisCached.del(RedisConstant.EXT_EVENT_PERSON_NO_KEY + oldExtEventPersonNo);
//                    }
//                    //添加新的安防平台人员编号缓存
//                    redisCached.set(RedisConstant.EXT_EVENT_PERSON_NO_KEY + extEventPersonNo, extEventPersonNo);
//                    oldBindCardDTO.setExtEventPersonNo(extEventPersonNo);
//                }
                bindCardCached.hsetBindCardInfo(oldBindCardDTO);
            }
        }

        if (jobId != null) {
            //修改人员信息时查询作业ID与人员ID的关系，如果存在则不添加，如果不存在，则新添加一条绑定关系
            JobPersonnel jp = jobPersonnelMapper.selectOne(Wrappers.<JobPersonnel>lambdaQuery()
                    .eq(JobPersonnel::getJobId, jobId)
                    .eq(JobPersonnel::getPersonnelId, workPersonnel.getWorkPersonnelId()));
            if (jp == null) {
                //新添加一条作业与人员的绑定关系
                jp = new JobPersonnel();
                jp.setJobId(jobId);
                jp.setPersonnelId(workPersonnel.getWorkPersonnelId());
                jobPersonnelMapper.insert(jp);
                String roomNo = job.getRoomNo();
                //修改敏感区域工单缓存
                String str = redisCached.hget(RedisConstant.JOB_ROOM_NO_INFO_KEY + roomNo, jobId + "");
                if (StringUtils.isNotBlank(str)) {
                    Job jobCached = JSONObject.parseObject(str, Job.class);
                    if (jobCached != null) {
                        List<String> temporaryEmpNos = jobCached.getTemporaryEmpNos();
                        if (CollectionUtils.isEmpty(temporaryEmpNos)) {
                            temporaryEmpNos = new ArrayList<>();
                        }
                        temporaryEmpNos.add(workPersonnel.getTemporaryEmpNo());
                        jobCached.setTemporaryEmpNos(temporaryEmpNos);
                        redisCached.hset(RedisConstant.JOB_ROOM_NO_INFO_KEY + roomNo, jobId + "", JSON.toJSONString(jobCached));
                    }
                }
            }
        }
        workPersonnelCached.setWorkPersonnelInfo(workPersonnel);
        return workPersonnel.getWorkPersonnelId();
    }

//    public Integer addAndUpdateWorkPersonnel(WorkPersonnelDTO dto) {
//        Integer workPersonnelId = dto.getWorkPersonnelId();
//        Long jobId = dto.getJobId();
//        Job job = null;
//        if (jobId != null) {
//            job = jobMapper.selectById(jobId);
//            if (job == null) {
//                throw new ApiException(JsonResultEnum.JOB_INFO_IS_NULL);
//            }
//        }
//        //人员组校验
//        Integer groupId = dto.getGroupId();
//        if (groupId != null) {
//            PersonGroup personGroup = personGroupMapper.selectOne(Wrappers.<PersonGroup>lambdaQuery()
//                    .eq(PersonGroup::getGroupType, NumericalConstants.TWO).eq(PersonGroup::getGroupId, groupId));
//            ParamCheckUtil.isNull(personGroup, JsonResultEnum.PERSON_GROUP_EXIST);
//        }
//        WorkPersonnel workPersonnel = new WorkPersonnel();
//        BeanUtil.copyProperties(dto, workPersonnel);
//        workPersonnel.setGroupId(groupId);
//        workPersonnel.setAge(getAgeByIdCodeNo(dto.getIdCardNo()));
//        WorkPersonnel work = workPersonnelMapper.selectOne(Wrappers.<WorkPersonnel>lambdaQuery()
//                .eq(WorkPersonnel::getIdCardNo, dto.getIdCardNo()));
//        if (workPersonnel.getGroupId() == null) {
//            workPersonnel.setGroupId(NumericalConstants.ZERO);
//        }
//        String idCardNo = workPersonnel.getIdCardNo();
//        if (workPersonnelId == null) {
//            //新增
//            if (work == null) {
//                //身份证去重
//                if (workPersonnelMapper.exists(Wrappers.<WorkPersonnel>lambdaQuery().eq(WorkPersonnel::getIdCardNo, idCardNo))) {
//                    throw new ApiException(JsonResultEnum.ID_CARD_NO_EXIST);
//                }
//                //给人员信息生成一个唯一工号
//                String id = IdUtil.objectId();
//                workPersonnel.setTemporaryEmpNo(id);
//                //新增人员信息表数据
//                workPersonnelMapper.insert(workPersonnel);
//            } else {
//                //身份证去重
//                if (workPersonnelMapper.exists(Wrappers.<WorkPersonnel>lambdaQuery().eq(WorkPersonnel::getIdCardNo, idCardNo)
//                        .ne(WorkPersonnel::getWorkPersonnelId, work.getWorkPersonnelId()))) {
//                    throw new ApiException(JsonResultEnum.ID_CARD_NO_EXIST);
//                }
//                workPersonnel.setWorkPersonnelId(work.getWorkPersonnelId());
//                workPersonnel.setTemporaryEmpNo(work.getTemporaryEmpNo());
//                //修改人员信息
//                workPersonnelMapper.updateById(workPersonnel);
//            }
//            //新增作业工单与作业人员信息关联表数据
////            JobPersonnel jobPersonnel = new JobPersonnel();
////            jobPersonnel.setJobId(jobId);
////            jobPersonnel.setPersonnelId(workPersonnel.getWorkPersonnelId());
////            jobPersonnelMapper.insert(jobPersonnel);
//        } else {
//            //身份证去重
//            if (workPersonnelMapper.exists(Wrappers.<WorkPersonnel>lambdaQuery().eq(WorkPersonnel::getIdCardNo, idCardNo)
//                    .ne(WorkPersonnel::getWorkPersonnelId, workPersonnelId))) {
//                throw new ApiException(JsonResultEnum.ID_CARD_NO_EXIST);
//            }
//            workPersonnel.setTemporaryEmpNo(work.getTemporaryEmpNo());
//            //修改人员信息
//            workPersonnelMapper.updateById(workPersonnel);
//        }
//        if (groupId != null && !groupId.equals(NumericalConstants.ZERO)) {
//            BindPersonGroup bindPersonGroup = new BindPersonGroup(workPersonnel);
//            redisCached.hset(RedisConstant.GROUP_PERSONNEL_INFO + groupId, workPersonnel.getTemporaryEmpNo(), JSON.toJSONString(bindPersonGroup));
//        } else {
//            if (work != null) {
//                redisCached.hdel(RedisConstant.GROUP_PERSONNEL_INFO + work.getGroupId(), work.getTemporaryEmpNo());
//            }
//
//        }
//        if (jobId != null) {
//            //修改人员信息时查询作业ID与人员ID的关系，如果存在则不添加，如果不存在，则新添加一条绑定关系
//            JobPersonnel jp = jobPersonnelMapper.selectOne(Wrappers.<JobPersonnel>lambdaQuery()
//                    .eq(JobPersonnel::getJobId, jobId)
//                    .eq(JobPersonnel::getPersonnelId, workPersonnel.getWorkPersonnelId()));
//            if (jp == null) {
//                //新添加一条作业与人员的绑定关系
//                jp = new JobPersonnel();
//                jp.setJobId(jobId);
//                jp.setPersonnelId(workPersonnel.getWorkPersonnelId());
//                jobPersonnelMapper.insert(jp);
//                String roomNo = job.getRoomNo();
//                //修改敏感区域工单缓存
//                String str = redisCached.hget(RedisConstant.JOB_ROOM_NO_INFO_KEY + roomNo, jobId + "");
//                if (StringUtils.isNotBlank(str)) {
//                    Job jobCached = JSONObject.parseObject(str, Job.class);
//                    if (jobCached != null) {
//                        List<String> temporaryEmpNos = jobCached.getTemporaryEmpNos();
//                        if (CollectionUtils.isEmpty(temporaryEmpNos)) {
//                            temporaryEmpNos = new ArrayList<>();
//                        }
//                        temporaryEmpNos.add(workPersonnel.getTemporaryEmpNo());
//                        jobCached.setTemporaryEmpNos(temporaryEmpNos);
//                        redisCached.hset(RedisConstant.JOB_ROOM_NO_INFO_KEY + roomNo, jobId + "", JSON.toJSONString(jobCached));
//                    }
//                }
//            }
//        }
//        //由于之前作业人员缓存有三个月时效性，防止缓存中没有作业人员数据，所以在此做补充
//        workPersonnelCached.setWorkPersonnelInfo(workPersonnel);
//        return workPersonnel.getWorkPersonnelId();
//    }

    /**
     * 根据身份证号计算年龄
     *
     * @param idCardNo
     * @return java.lang.Integer
     * @author ljx
     * @time 2024/10/21 16:23
     */
    public Integer getAgeByIdCodeNo(String idCardNo) {
        if (StringUtils.isBlank(idCardNo)) {
            return null;
        }
        String year = idCardNo.substring(6, 10);
        String month = idCardNo.substring(10, 12);
        String day = idCardNo.substring(12, 14);
        String dateOfBirth = year + "-" + month + "-" + day + " 00:00:00";
        return DateUtils.getAgeByDate(dateOfBirth);
    }

    /**
     * 分页获取作业人员信息
     *
     * @param pageDTO
     * @param name
     * @param groupId
     * @return
     */
    @Override
    public JsonResult<List<WorkPersonnel>> queryWorkPersonnelPages(PageDTO pageDTO, String name, Integer groupId) {
        IPage<WorkPersonnel> page = new Page<>(pageDTO.getPageNumber(), pageDTO.getPageSize());
        QueryWrapper<WorkPersonnel> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotEmpty(name)) {
            queryWrapper.lambda().like(WorkPersonnel::getName, name);
        }
        if (groupId != null) {
            queryWrapper.lambda().eq(WorkPersonnel::getGroupId, groupId);
        }
        queryWrapper.lambda().orderByDesc(WorkPersonnel::getCreateTime);
        IPage<WorkPersonnel> iPage = workPersonnelMapper.selectPage(page, queryWrapper);
        List<WorkPersonnel> workPersonnelList = iPage.getRecords();
        if (!CollectionUtils.isEmpty(workPersonnelList)) {
            List<Integer> groupIds = workPersonnelList.stream().map(WorkPersonnel::getGroupId).collect(Collectors.toList());
            Map<Integer, PersonGroup> personGroupMap = null;
            if (!CollectionUtils.isEmpty(groupIds)) {
                List<PersonGroup> personGroups = personGroupMapper.selectList(Wrappers.<PersonGroup>lambdaQuery()
                        .in(PersonGroup::getGroupId, groupIds).eq(PersonGroup::getGroupType, NumericalConstants.TWO));
                if (!CollectionUtils.isEmpty(personGroups)) {
                    personGroupMap = personGroups.stream().collect(Collectors.toMap(PersonGroup::getGroupId, Function.identity()));
                }
            }
            for (WorkPersonnel workPersonnel : workPersonnelList) {
                workPersonnel.setAge(getAgeByIdCodeNo(workPersonnel.getIdCardNo()));
                if (!CollectionUtils.isEmpty(personGroupMap)) {
                    PersonGroup personGroup = personGroupMap.get(workPersonnel.getGroupId());
                    if (personGroup != null) {
                        workPersonnel.setGroupName(personGroup.getGroupName());
                    }
                }
            }
        }
        return JsonResult.success(workPersonnelList, iPage.getTotal());
    }

    @Override
    public List<Job> fuzzyQueryJobList(String value) {
        int pageSize = 20;
        if (StringUtils.isEmpty(value)) {
            // 如果传入空，默认按照设备时间返回20条数据
            List<Job> jobList = jobMapper.selectListDescTime(pageSize);
            return jobList;
        }
        List<Job> jobs = jobMapper.selectFuzzyByJobIdAndDirector(value, pageSize);
        return jobs;
    }

    /**
     * 根据工单获取异常提醒信息
     *
     * @param jobId
     * @return
     */
    @Override
    public JsonResult<JobRemindVO> JobRemindVO(Long jobId) {
        JobRemindVO jobRemindVO = new JobRemindVO();
        if (jobId == null) {
            return JsonResult.fail(JsonResultEnum.NO_DATA);
        }
        Job job = jobMapper.selectById(jobId);
        if (job == null) {
            return JsonResult.fail(JsonResultEnum.NO_DATA);
        }
        Date startTime = job.getStartTime();
        Date endTime = job.getEndTime();
        if (startTime == null || endTime == null) {
            return JsonResult.fail(JsonResultEnum.NO_DATA);
        }
        long currentTimeMillis = System.currentTimeMillis();
        if (startTime.getTime() < currentTimeMillis && endTime.getTime() > currentTimeMillis) {
            List<WorkPersonnel> workPersonnelList = jobPersonnelMapper.selectJobIdByPersonnelList(jobId);
            if (CollectionUtils.isEmpty(workPersonnelList)) {
                return JsonResult.fail(JsonResultEnum.NO_DATA);
            }
            List<WorkPersonnelVO> workPersonnelVOS = new ArrayList<>();
            String roomNo = job.getRoomNo();
            if (StringUtils.isNotBlank(roomNo)) {
                Room room = roomMapper.selectOne(Wrappers.<Room>lambdaQuery().eq(Room::getRoomNo, roomNo));
                if (room != null) {
                    String roomPoint = room.getRoomPoint();
                    JSONObject jsonObject = JSON.parseObject(roomPoint);
                    JSONArray startArray = jsonObject.getJSONArray("start");
                    JSONArray endArray = jsonObject.getJSONArray("end");
                    //矩形的高度是一致的
                    Double rectY = startArray.getDouble(1);
                    //已知起点跟对角线的点,计算出第二跟第四的点
                    //[1,0.1,0]
                    Double[] onePos = new Double[]{startArray.getDouble(0), rectY, startArray.getDouble(2)};
                    //[2,0.1,0]
                    Double[] twoPos = new Double[]{endArray.getDouble(0), rectY, startArray.getDouble(2)};
                    //[2,0.1,1]
                    Double[] therePos = new Double[]{endArray.getDouble(0), rectY, endArray.getDouble(2)};
                    //[1,0.1,1]
                    Double[] fourPos = new Double[]{startArray.getDouble(0), rectY, endArray.getDouble(2)};
                    String areaCoordinates = onePos[0] + "," + onePos[2] + "|" + twoPos[0] + "," + twoPos[2] + "|" + therePos[0] + "," + therePos[2] + "|" + fourPos[0] + "," + fourPos[2];
                    Integer mapId = room.getMapId();
                    if (mapId != null) {
                        List<Integer> groupIds = workPersonnelList.stream().map(WorkPersonnel::getGroupId).collect(Collectors.toList());
                        Map<Integer, PersonGroup> personGroupMap = null;
                        if (!CollectionUtils.isEmpty(groupIds)) {
                            List<PersonGroup> personGroups = personGroupMapper.selectList(Wrappers.<PersonGroup>lambdaQuery()
                                    .in(PersonGroup::getGroupId, groupIds).eq(PersonGroup::getGroupType, NumericalConstants.TWO));
                            if (!CollectionUtils.isEmpty(personGroups)) {
                                personGroupMap = personGroups.stream().collect(Collectors.toMap(PersonGroup::getGroupId, Function.identity()));
                            }
                        }
                        for (WorkPersonnel workPersonnel : workPersonnelList) {
                            WorkPersonnelVO workPersonnelVO = null;
                            String temporaryEmpNo = workPersonnel.getTemporaryEmpNo();
                            BindCardDTO bindCardDTO = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_EMP_NO_KEY + temporaryEmpNo);
                            if (bindCardDTO != null) {
                                String str = redisCached.get(UWBPosConstant.REDIS_TAG_POS_KEY + bindCardDTO.getDeviceName());
                                if (StringUtils.isNotBlank(str)) {
                                    HttpTagPosVO httpTagPosVO = JSONObject.parseObject(str, HttpTagPosVO.class);
                                    long time = httpTagPosVO.getTime();
                                    //三分钟没推送位置数据代表离线，肯定不在范围内
                                    if (currentTimeMillis - time > 1000 * 60 * 3) {
                                        workPersonnelVO = getWorkPersonnelVO(workPersonnel, personGroupMap);
                                    } else {
                                        double[] pos = httpTagPosVO.getPos();
                                        double aX = pos[0];
                                        //人员位置跟3D模型的不一致,人员位置的y应换成第三位
                                        double aY = pos[2];
                                        //取反值
                                        double aZ = -pos[1];
                                        boolean inPoly = FindMediaDevUtils.IsPathMapInPoly(aX, aZ, areaCoordinates,
                                                httpTagPosVO.getMapId(), mapId);
                                        //不在范围内
                                        if (!inPoly) {
                                            workPersonnelVO = getWorkPersonnelVO(workPersonnel, personGroupMap);
                                        }
                                    }
                                }
                            } else {
                                workPersonnelVO = getWorkPersonnelVO(workPersonnel, personGroupMap);
                            }
                            if (workPersonnelVO != null) {
                                workPersonnelVOS.add(workPersonnelVO);
                            }
                        }
                    }
                }
            }
            if (!CollectionUtils.isEmpty(workPersonnelVOS)) {
                String dateTime = DateUtils.dateToStr(new Date());
                jobRemindVO.setAnomalyType(NumericalConstants.ONE);
                jobRemindVO.setDirector(job.getDirector());
                jobRemindVO.setEnrollTime(dateTime);
                jobRemindVO.setTriggeringTime(dateTime);
                jobRemindVO.setWorkPersonnelVOS(workPersonnelVOS);
                return JsonResult.success(jobRemindVO);
            } else {
                return JsonResult.fail(JsonResultEnum.NO_DATA);
            }
        } else {
            return JsonResult.fail(JsonResultEnum.NO_DATA);
        }
    }

    /**
     * 删除人员与工单的绑定关系
     *
     * @param jobId
     * @param workPersonnelId
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/11/11 9:31
     */
    @Override
    public JsonResult deleteJobAssociation(Long jobId, Integer workPersonnelId) {
        ParamCheckUtil.isNull(jobId);
        ParamCheckUtil.isNull(workPersonnelId);
        Job job = jobMapper.selectById(jobId);
        WorkPersonnel workPersonnel = workPersonnelMapper.selectById(workPersonnelId);
        ParamCheckUtil.isNull(job, JsonResultEnum.JOB_INFO_IS_NULL);
        ParamCheckUtil.isNull(workPersonnel, JsonResultEnum.PERSONNEL_NOT_EXIST);
        jobPersonnelMapper.delete(new QueryWrapper<JobPersonnel>().lambda().eq(JobPersonnel::getJobId, jobId).eq(JobPersonnel::getPersonnelId, workPersonnelId));
        String roomNo = job.getRoomNo();
        //修改敏感区域工单缓存
        String str = redisCached.hget(RedisConstant.JOB_ROOM_NO_INFO_KEY + roomNo, jobId + "");
        if (StringUtils.isNotBlank(str)) {
            Job jobCached = JSONObject.parseObject(str, Job.class);
            if (jobCached != null) {
                List<String> temporaryEmpNos = jobCached.getTemporaryEmpNos();
                if (!CollectionUtils.isEmpty(temporaryEmpNos)) {
                    temporaryEmpNos.remove(workPersonnel.getTemporaryEmpNo());
                }
                jobCached.setTemporaryEmpNos(temporaryEmpNos);
                redisCached.hset(RedisConstant.JOB_ROOM_NO_INFO_KEY + roomNo, jobId + "", JSON.toJSONString(jobCached));
            }
        }
        return JsonResult.success();
    }

    /**
     * 获取作业人员信息VO
     *
     * @param workPersonnel
     * @param personGroupMap
     * @return com.bsj.power.common.def.vo.pls.WorkPersonnelVO
     * @author ljx
     * @time 2024/9/26 10:00
     */
    private WorkPersonnelVO getWorkPersonnelVO(WorkPersonnel workPersonnel, Map<Integer, PersonGroup> personGroupMap) {
        WorkPersonnelVO workPersonnelVO = new WorkPersonnelVO();
        BeanUtils.copyProperties(workPersonnel, workPersonnelVO);
        workPersonnelVO.setAge(getAgeByIdCodeNo(workPersonnel.getIdCardNo()));
        if (!CollectionUtils.isEmpty(personGroupMap)) {
            PersonGroup personGroup = personGroupMap.get(workPersonnel.getGroupId());
            if (personGroup != null) {
                workPersonnelVO.setGroupName(personGroup.getGroupName());
            }
        }
        return workPersonnelVO;
    }

    /**
     * QC类型转换
     *
     * @param wpm1
     * @return java.lang.Integer
     * @author ljx
     * @time 2024/7/11 11:44
     */
    private Integer wpm1ToType(String wpm1) {
        Integer type;
        switch (wpm1) {
            case "A":
                type = NumericalConstants.ONE;
                break;
            case "B":
                type = NumericalConstants.TWO;
                break;
            case "C":
                type = NumericalConstants.THREE;
                break;
            default:
                type = NumericalConstants.ZERO;
                log.info("错误的QC类型{}", wpm1);
                break;
        }
        return type;
    }


    /**
     * 作业效率计算
     *
     * @param jobs        作业集合
     * @param jobRankList 计算结果
     */
    private void calculationEfficiencyRanking(List<Job> jobs, List<JobRank> jobRankList) {
        //个人排行,当前按照负责人区分，不确定每个作业是否由一个人完成
        Map<String, List<Job>> directorList = jobs.stream().filter(job -> StringUtils.isNotBlank(job.getDirectorId())).collect(Collectors.groupingBy(Job::getDirectorId));
        Iterator<Map.Entry<String, List<Job>>> iterator = directorList.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, List<Job>> entry = iterator.next();
            String key = entry.getKey();
            Personnel personnel = personnelMapper.selectOne(Wrappers.<Personnel>lambdaQuery().eq(Personnel::getDirectorId, key));
            String name = personnel != null ? personnel.getName() : "未知";
            List<Job> value = entry.getValue();
            //已完成数量
            long completeCount = value.stream().filter(item -> item.getStatus() == 2).count();
            if (completeCount == 0) {
                continue;
            }
            JobRank jobRank = JobRank.builder().name(name).rate(Double.parseDouble(String.format("%.2f", NumberUtil.div(completeCount, jobs.size(), 2)))).build();
            jobRankList.add(jobRank);
        }
    }

    /**
     * 计算作业时长趋势
     *
     * @param completeJobList  符合计算条件的作业集合
     * @param workDurationList 按每日时间计算出来当日作业时长
     */
    private void calculateHomeworkDuration(List<Job> completeJobList, List<WorkDuration> workDurationList) {
        List<JobVO> jobVOList = new ArrayList<>();
        completeJobList.stream().forEach(item -> {
            JobVO vo = new JobVO();
            BeanUtil.copyProperties(item, vo);
            vo.setTempStartTime(DateUtils.dateToStr(yearMonthDay, item.getStartTime()));
            vo.setStartTime(DateUtils.dateToStr(item.getStartTime()));
            vo.setEndTime(DateUtils.dateToStr(item.getEndTime()));
            jobVOList.add(vo);
        });
        Map<String, List<JobVO>> durationMap = jobVOList.stream().collect(Collectors.groupingBy(JobVO::getStartTime));
        String startTime = "";
        String endTime = "";
        for (Map.Entry<String, List<JobVO>> item : durationMap.entrySet()) {
            String itemKey = item.getKey();
            List<JobVO> itemValue = item.getValue();
            if (!CollectionUtils.isEmpty(itemValue)) {
                //计算每个作业的完成时长
                AtomicReference<Long> minutes = new AtomicReference<>(0L);
                for (JobVO vj : itemValue) {
                    startTime = vj.getStartTime();
                    endTime = vj.getEndTime();
                    if (!StringUtils.isAnyBlank()) {
                        Date start = DateUtils.strToDate(startTime);
                        Date end = DateUtils.strToDate(endTime);
                        //作业完成时长
                        minutes.updateAndGet(v -> v + DateUtils.minusDateToMinutes(start, end));
                    }
                }
                itemKey = DateUtils.dateToStr(DateUtils.yearMonthDay, DateUtils.strToDate(itemKey));
                WorkDuration workDuration = WorkDuration.builder().day(itemKey).minutes(minutes.get()).build();
                workDurationList.add(workDuration);
            }
        }
        //如果没有数据也显示一条当天时长为0的数据
        if (workDurationList.isEmpty()) {
            WorkDuration workDuration = WorkDuration.builder()
                    .day(DateUtils.dateToStr(yearMonthDay, new Date())).minutes(0L).build();
            workDurationList.add(workDuration);
        }
        //按日期正序
        workDurationList.sort(Comparator.comparing(WorkDuration::getDay));
    }

}
